package keter.mongo.base;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jfinal.ext.plugin.monogodb.MongoKit;
import com.jfinal.plugin.activerecord.Record;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

public  abstract class MongoBase<R extends MongoBase>  extends Record {
    /**
     * Logger for this class
     */
    private static final Logger logger = LoggerFactory.getLogger(MongoBase.class);    
    
    /**DBCollection coll: 获取集合*/
    DBCollection coll  = MongoKit.getDB().getCollection(this.getType());
    protected Map<String, Object> filter = Maps.newHashMap();
    
    
    /**
     * <p>Method ：getAttrs
     * <p>Description : 通过map读取属性字段(for jstl)
     * 
     * @see com.jfinal.plugin.activerecord.Model#getAttrs()
     * @author  gulixing@msn.com
     * @version 1.0.0
     */
    public Map<String, Object> getAttrs(){
        return super.getColumns();
    }
    
    
//    public BaseRecord(){
//       coll = MongoKit.getDB().getCollection(this.getType());
//       logger.info("init coll");
//       coll = MongoKit.getDB().getCollection("haha");
//    }
    
    /**
     * <p>Method ：getType
     * <p>Description : 以当前类名(小写)作为默认类型
     * 如："keter.mongo.model.BaseRecord" 的类型名为"baserecord"
     * @return 
     * @author  gulixing@msn.com
     * @version 1.0.0
     */
    
    public  String getType(){
    	String className = getClass().getName();
		return StringUtils.lowerCase(className.substring(
				className.lastIndexOf(".")+1, 
				className.length()) 
			);
    }
    
    public ObjectId save(){
        BasicDBObject bo = toDbObject(this);
        coll.save(bo);
        return (ObjectId) bo.get("_id");
    }
    
    public  R findById(ObjectId id) throws Exception{
    	return toR(coll.findOne(id)) ;
    }
    
    public  R findById(String id) throws Exception{
        return findById(new ObjectId(id)) ;
    }
    
    public  String findJsonById(ObjectId id) throws Exception{
        return coll.findOne(id).toString();
    }
    
    public List<R> findAll() throws Exception {    
       DBCursor dbCursor = coll.find();
       List<R> records = Lists.newArrayList();
       while (dbCursor.hasNext()) {
           records.add(toR(dbCursor.next()));
       }
       return records;
    }
    
    public List<R> find(Map<String, Object> filter) throws Exception {    
        BasicDBObject conditons = new BasicDBObject();
        buildFilter(filter, conditons);
        DBCursor dbCursor = coll.find(conditons);
        List<R> records = Lists.newArrayList();
        while (dbCursor.hasNext()) {
            records.add(toR(dbCursor.next()));
        }
        return records;
    }
    
    public List<R> findIn(String fileld, String[] filter) throws Exception {
    	DBObject query = buildInFilter(fileld,filter);
        DBCursor dbCursor = coll.find(query);
    	List<R> records = Lists.newArrayList();
    	while (dbCursor.hasNext()) {
    		records.add(toR(dbCursor.next()));
    	}
    	return records;
    }
    
    public R findOne(Map<String, Object> filter) throws Exception {    
    	BasicDBObject conditons = new BasicDBObject();
    	buildFilter(filter, conditons);
    	return coll.findOne(conditons)==null?null:toR(coll.findOne(conditons));
    }
    
    private static BasicDBObject toDbObject(Record record) {
        BasicDBObject object = new BasicDBObject();
        for (Entry<String, Object> e : record.getColumns().entrySet()) {
            object.append(e.getKey(), e.getValue());
        }
        return object;
    }
    
    private  R toR(DBObject dbObject) throws InstantiationException, IllegalAccessException {
		if(dbObject == null){
		    return null;
		}
        Class<? extends MongoBase> recordClass = getClass();
		Record record = recordClass.newInstance();
		record.setColumns(dbObject.toMap());
        return (R) record;
    }
    
    private static void buildLike(Map<String, Object> like, BasicDBObject conditons) {
        if (like != null) {
            Set<Entry<String, Object>> entrySet = like.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                String key = entry.getKey();
                Object val = entry.getValue();
                conditons.put(key, MongoKit.getLikeStr(val));
            }
        }
    }

    private static void buildFilter(Map<String, Object> filter, BasicDBObject conditons) {
        if (filter != null) {
            Set<Entry<String, Object>> entrySet = filter.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                String key = entry.getKey();
                Object val = entry.getValue();
                conditons.put(key, val);
            }
        }
    }
    
	private DBObject buildInFilter(String filed, String[] filter) {
		DBObject query = new BasicDBObject();       
        BasicDBList values = new BasicDBList();
		for (String string : filter) {
			values.add(string);
		}
        query.put(filed, new BasicDBObject("$in", values));
		return query;
	}
 }